const axios = require('axios');
const fs = require('fs');
const path = require('path');
const readline = require('readline');
const { ArgumentParser } = require('argparse');
const FormData = require('form-data');

class FileManagementClient {
    constructor(host, port, user, pwd) {
        this.base_url = `http://${host}:${port}`;
        this.user = user;
        this.pwd = pwd;
        this.session = axios.create({
            baseURL: this.base_url,
            timeout: 5000
        });
    }

    async login() {
        try {
            const response = await this.session.post('/login', {
                username: this.user,
                password: this.pwd
            });
            
            if (response.status === 200 && response.data.token) {
                this.session.defaults.headers.common['Authorization'] = `Bearer ${response.data.token}`;
                console.log("登录成功");
                return true;
            } else {
                console.error("登录失败：", response.data.message);
                return false;
            }
        } catch (error) {
            console.error("登录失败：", error.response ? error.response.data.message : error.message);
            return false;
        }
    }

    async upload(file, remotePath) {
        try {
            const filePath = path.join(process.cwd(), file);
            const formData = new FormData();
            formData.append('file', fs.createReadStream(filePath));
            const response = await this.session.post('/upload', formData, {
                params: { path: remotePath },
                headers: formData.getHeaders()
            });
            console.log(response.data.message);
        } catch (error) {
            console.error('上传失败:', error.response ? error.response.data.message : error.message);
        }
    }

    async download(file, remotePath) {
        try {
            const response = await this.session.get('/download', {
                params: { file, path: remotePath },
                responseType: 'stream'
            });
            const writer = fs.createWriteStream(path.join(process.cwd(), file));
            response.data.pipe(writer);
            return new Promise((resolve, reject) => {
                writer.on('finish', () => {
                    console.log('文件下载成功');
                    resolve();
                });
                writer.on('error', reject);
            });
        } catch (error) {
            console.error('下载失败:', error.response ? error.response.data.message : error.message);
        }
    }

    async deleteFile(name, remotePath) {
        try {
            const response = await this.session.delete('/delete', {
                data: { name, path: remotePath }
            });
            console.log(response.data.message);
        } catch (error) {
            console.error('删除失败:', error.response ? error.response.data.message : error.message);
        }
    }

    async rename(oldName, newName, remotePath) {
        try {
            const response = await this.session.put('/rename', {
                oldName,
                newName,
                path: remotePath
            });
            console.log(response.data.message);
        } catch (error) {
            console.error('重命名失败:', error.response ? error.response.data.message : error.message);
        }
    }

    async mkdir(dir, remotePath) {
        try {
            const response = await this.session.post('/mkdir', {
                name: dir,
                path: remotePath
            });
            console.log(response.data.message);
        } catch (error) {
            console.error('创建目录失败:', error.response ? error.response.data.message : error.message);
        }
    }

    async list(remotePath) {
        try {
            const response = await this.session.get('/list', {
                params: { path: remotePath }
            });
            response.data.items.forEach(item => {
                console.log(`${item.name}${item.isDir ? '/' : ''}`);
            });
        } catch (error) {
            console.error('列表获取失败:', error.response ? error.response.data.message : error.message);
        }
    }

    async cd(dir) {
        try {
            const response = await this.session.post('/cd', {
                path: dir
            });
            console.log(response.data.message);
            return dir;
        } catch (error) {
            console.error('更改远程目录失败:', error.response ? error.response.data.message : error.message);
            return null;
        }
    }
}

async function main() {
    const parser = new ArgumentParser({
        description: "文件管理客户端"
    });
    
    parser.add_argument("--host", {
        default: '127.0.0.1',
        help: "服务器主机名"
    });
    parser.add_argument("--port", {
        type: 'int',
        default: 8080,
        help: "服务器端口"
    });
    parser.add_argument("--user", {
        required: true,
        help: "用户名 (必需参数)"
    });
    parser.add_argument("--pwd", {
        required: true,
        help: "密码 (必需参数)"
    });

    try {
        const args = parser.parse_args();
        
        if (!args.user || !args.pwd) {
            console.error('错误: 必须提供用户名和密码');
            console.error('使用示例: node client.js --user=用户名 --pwd=密码');
            process.exit(1);
        }

        const client = new FileManagementClient(args.host, args.port, args.user, args.pwd);
        
        if (!await client.login()) {
            console.error("登录失败，程序退出");
            process.exit(1);
        }

        console.log("开始文件管理操作");
        let remoteCurrentDir = '/';

        const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });

        rl.setPrompt('> ');
        rl.prompt();

        rl.on('line', async (line) => {
            const [command, ...args] = line.trim().split(' ');

            try {
                switch (command) {
                    case 'upload':
                        if (args.length !== 1) {
                            console.error('用法: upload <file>');
                        } else {
                            await client.upload(args[0], remoteCurrentDir);
                        }
                        break;
                    case 'download':
                        if (args.length !== 1) {
                            console.error('用法: download <file>');
                        } else {
                            await client.download(args[0], remoteCurrentDir);
                        }
                        break;
                    case 'delete':
                        if (args.length !== 1) {
                            console.error('用法: delete <file/dir>');
                        } else {
                            await client.deleteFile(args[0], remoteCurrentDir);
                        }
                        break;
                    case 'rename':
                        if (args.length !== 2) {
                            console.error('用法: rename <old-name> <new-name>');
                        } else {
                            await client.rename(args[0], args[1], remoteCurrentDir);
                        }
                        break;
                    case 'mkdir':
                        if (args.length !== 1) {
                            console.error('用法: mkdir <dir>');
                        } else {
                            await client.mkdir(args[0], remoteCurrentDir);
                        }
                        break;
                    case 'list':
                        await client.list(remoteCurrentDir);
                        break;
                    case 'lcd':
                        if (args.length !== 1) {
                            console.error('用法: lcd <dir>');
                        } else if (!path.isAbsolute(args[0])) {
                            console.error('请使用绝对路径');
                        } else {
                            try {
                                process.chdir(args[0]);
                                console.log(`本地当前目录已更改为: ${process.cwd()}`);
                            } catch (error) {
                                console.error('更改本地目录失败:', error.message);
                            }
                        }
                        break;
                    case 'lpwd':
                        console.log(`本地当前目录: ${process.cwd()}`);
                        break;
                    case 'rcd':
                        if (args.length !== 1) {
                            console.error('用法: rcd <dir>');
                        } else if (!path.isAbsolute(args[0])) {
                            console.error('请使用绝对路径');
                        } else {
                            const newPath = await client.cd(args[0]);
                            if (newPath) remoteCurrentDir = newPath;
                        }
                        break;
                    case 'rpwd':
                        console.log(`远程当前目录: ${remoteCurrentDir}`);
                        break;
                    case 'help':
                        console.log(`
可用命令:
  upload <file>                  上传本地当前目录的文件到服务器的当前目录
  download <file>                下载服务器当前目录的文件到本地当前目录
  delete <file/dir>              删除服务器当前目录的文件或目录
  rename <old-name> <new-name>   修改服务器当前目录的文件或目录名称
  mkdir <dir>                    在服务器当前目录创建子目录
  list                          查看服务器当前目录下的文件或目录
  lcd <dir>                     修改本地当前目录（需要绝对路径）
  lpwd                         显示本地当前目录
  rcd <dir>                     修改服务器当前目录（需要绝对路径）
  rpwd                         显示服务器当前目录
  help                         显示此帮助信息
  exit                         退出程序
                        `);
                        break;
                    case 'exit':
                        console.log('再见！');
                        rl.close();
                        process.exit(0);
                    default:
                        console.error('未知命令。输入 help 查看可用命令。');
                }
            } catch (error) {
                console.error('执行命令时出错:', error.message);
            }

            rl.prompt();
        });

        rl.on('close', () => {
            console.log('再见！');
            process.exit(0);
        });

    } catch (error) {
        if (error.message.includes('argument')) {
            console.error('命令行参数错误！');
            console.error('正确用法: node client.js --user=用户名 --pwd=密码 [--host=主机名] [--port=端口号]');
        } else {
            console.error('程序出错:', error.message);
        }
        process.exit(1);
    }
}

main().catch(error => {
    console.error('程序出错:', error);
    process.exit(1);
});

